/****************************************
 ****************************************
 **   This document written by CTonk.  **
 **         ctonk@hotmail.com          **
 ****************************************
 ****************************************/

// world.cpp

#ifndef CPP_WORLD
#define CPP_WORLD

#include "world.h"
#include "Tick.h"
#include< fstream >



World::World()
{
	_exists = true;
	_copyover = false;
	_shutdown = false;
	InitializeCommands();
	InitializeQuotes();
	_clock = new Time::clock( TickPtr );
	srand( _clock->GetSeconds() );
	_clock->SetNextFire( UPPER_TICK );

	// What version is the server?
	char temp[10];
	ifstream load( VERSION_FILE );
	load.getline( temp, 10 );
	_version << temp;
	load.close();

	// Load the world.
	World::Instance().Load();
}

World::~World() { }

void eat( ifstream& fin )
{// Makes file input easier.
	char c;
	fin.get( c );
	return;
}

Time::clock* World::GetClock()
{
	return _clock;
}

Character* World::FindCharacter( char* name )
{
	Character* ch;

	for ( int x=0; x < ChList.GetSize(); x++ )
	{
		ch = ChList[x];
		if ( same( ch->GetName(), name ) )
			return ch;
	}
	return ch;
}

Room* World::FindRoom( int vnum )
{
	Area* area = 0;
	Room* room = 0;

	for ( int x=0; x < _areas.GetSize(); x++ )
	{
		area = _areas[x];
		for ( int y=0; y < area->GetSize(); y++ )
		{
			room = area->GetRoom( y );
			if ( room->GetVnum() == vnum )
				return room;
		}
	}

	return _areas[0]->GetRoom( 0 );
}


bool World::Broadcast( char* message )
{
	for ( int x=0; x < ChList.GetSize(); x++ )
		ChList[x]->Send( message );

	return true;
}

bool World::Shutdown()
{
	Broadcast( "Shutdown.\n" );
	Instance().Save();
	_exists = false;
	return true;
}

bool World::Copyover()
{
	Broadcast( "World::Copyover()\n" );

	// Work on temporary port routing file!

	Spawn( TAKEOVER, "Symphony.exe", "-copyover" );

	return true;
}
bool World::CopyoverRecovery()
{
	Broadcast( "World::CopyoverRecovery()\n" );

	// Work on temporary port routing file!

	return true;
}
void World::Monitor()
{
	std::string buf;

    if ( SocketServer::Instance().Monitor() ) // Resolves true upon a new connection
	{
		Character* ch = new Character;
		ChList.Add( ch );
		ch->SetSocket( SocketServer::Instance()._socketList.back() );
		this->_areas[0]->GetRoom( 0 )->Add( ch );
		ch->SetRoom( 0 );

		buf << " {x=======================================================\n";
		buf << " ======           {W** {CSymphony{c " << _version << " {W**{x            ======\n";
		buf << " =======================================================\n\n";
		buf << "                    Thanks to Rendelven of 'Scratch' MUD\n";
		ch->Send( buf );
	}

	UpdateTimers();
	UpdateCharacters();
	HandleInput();

	return;
}

void World::FlushOutput()
{
	for ( int x=0; x < ChList.GetSize(); x++ )
		ChList[x]->FlushOutput();

	return;
}

void World::UpdateCharacters()
{ // private
	Creature* c = 0;

	// Check for input and disconnections
	for ( int x=0; x < ChList.GetSize(); x++ )
	{
		if ( !ChList[x]->GetSocket()->GotInput() )
			ChList[x]->SetGotinput( true );
		if ( ChList[x]->GetSocket()->IsDisconnected() )
			ChList[x]->SetConnected( false );
	}

	// Kill and remove the disconnected
	Character* ch = 0;
	for ( int x=0; x < ChList.GetSize(); x++ )
		if ( !ChList[x]->GetConnected() )
			ChList.Remove( ChList[x] );

	return;
}


void World::HandleInput()
{
	Character* c;

	for ( int x=0; x < ChList.GetSize(); x++ )
	{
		c = ChList[x];

		refresh();

		parse( c->GetSocket()->GetInput().c_str() );

		c->SetGotinput( !c->GetSocket()->GetInput().empty() );
		if ( c->GetGotinput() )
		{
			FindCommand( arg[0] )->Execute( c, inputs );
			c->GetSocket()->FlushInput();

		}
		c->GetSocket()->FlushInput();
	}

	UpdateCharacters();
	FlushOutput();

	return;
}

void World::UpdateTimers()
{
	if ( _clock->Check() )
		_clock->Fire( LOWER_TICK, UPPER_TICK );
	return;
}
void World::Schedule()
{
	return;
}
void World::FireEvent()
{
	return;
}

Command* World::FindCommand( char* name )
{
	Command* cmd = 0;

	char* t = new char[500]; // cmd->_name
	char* u = new char[500]; // cmd->_shortcut

	for ( std::list< Command* >::iterator CMD = CmdList.begin(); CMD != CmdList.end(); CMD++ )
	{
		cmd = (*CMD);
		strcpy( t, cmd->_name.c_str() );
		strcpy( u, cmd->_shortcut.c_str() );

		if ( same( name, t ) || same( name, u ) )
			return cmd;
	}

	delete [] t;
	delete [] u;

	return CmdList.back();
}

Magiclist< Area* >& World::GetAreas()
{
	return _areas;
}

Area* World::GetArea( int x )
{
	return _areas[x];
}

Area* World::SetArea( int number, Area& area )
{
	return ( _areas[ number ] = &area );
}

Area* World::AddArea()
{
	return ( _areas.Add() = new Area );
}

void World::AddAreas( int x )
{
	for ( int n=0; n < x; n++ )
		AddArea() = new Area;
	return;
}

void World::InitializeQuotes()
{
	char temp[1024];
	ifstream load( QUOTE_FILE );

	while ( load.peek() != EOF )
	{
		load.getline( temp, 1024, '~' );
		if ( temp[0] == '\n' )
			;
		else
		{
			_quotelist.Add();
			_quotelist[ _quotelist.GetSize() -1 ] = temp;
		}
		while ( load.peek() == '\n' )
			eat( load );
	}

	load.close();

	return;
}

std::string& World::RandomQuote()
{
	return _quotelist[ Time::Rand( 0, _quotelist.GetSize()-1 ) ];
}

std::string& World::Version()
{
	return _version;
}

void World::Save()
{
	Area* area = 0;
	char* file = new char[500];

	// Write all areas to AREA_FILE
	strcpy( file, AREA_FILE );
	std::ofstream save( file );
	save << World::Instance().GetAreas().GetSize() << '\n';
	for ( int x=0; x < World::Instance().GetAreas().GetSize(); x++ ) {
		area = World::Instance().GetArea( x );
		save << area->GetFile() << '\n';
	}
	save.close();

	// Save each area in sequence.
	for ( int x=0; x < World::Instance().GetAreas().GetSize(); x++ ) {
		area = World::Instance().GetArea( x );
		save.open( area->GetFile() );
		area->Save( save );
		save.close();
	}

	return;
}

void World::Load()
{
	Area* area = 0;
	int size = 0;
	char* temp = new char[500];

	ifstream load( AREA_FILE );
	while ( load.peek() != EOF ) {
		load.getline( temp, 500 );
		area = this->GetAreas().Add() = new Area;
		area->SetFile( temp );
	}
	load.close();

	for ( int x=0; x < this->GetAreas().GetSize(); x++ ) {
		area = this->GetArea( x );
		load.clear();
		load.open( area->GetFile() );
		area->Load( load );
		load.close();
	}

	return;
}




#endif // #ifndef CPP_WORLD
